/**
 * @description: 修改节点和边参数
 * @param {Graph} Graph
 * @Date: 2021-08-17 14:45:00
 */
export const drawGraph = (Graph) => {
  console.log("drawGraph");
  const {
    graph,
    height,
    width,
    nodes,
    edges,
    nodeMap,
    gColors,
    edgesMap,
    showNodes,
    showEdges,
  } = Graph;

  let curShowNodes = showNodes;
  let curShowEdges = $.extend(true, [], showEdges);
  let highlighting = false;
  let hideMap = new Map();

  function refreshDragedNodePosition(e) {
    const model = e.item.get("model");
    model.fx = e.x;
    model.fy = e.y;
  }

  graph.get("canvas").set("localRefresh", false);

  graph.on("node:dragstart", (e) => {
    graph.layout();
    refreshDragedNodePosition(e);
    hideContextMenu();
  });
  graph.on("node:drag", (e) => {
    refreshDragedNodePosition(e);
    hideContextMenu();
  });
  graph.on("node:dragend", (e) => {
    e.item.get("model").fx = null;
    e.item.get("model").fy = null;
    hideContextMenu();
  });

  graph.on("node:contextmenu", function (evt) {
    evt.preventDefault();
    console.log("object", evt.item.get("model"));
    $("#contextMenu")
      .css({
        left: evt.clientX + "px",
        top: evt.clientY + "px",
      })
      .attr("nodeId", evt.item.get("model").id);
  });

  graph.on("node:mouseenter", (e) => {
    const item = e.item;
    const model = item.getModel();
    const model1 = item.getEdges();

    highlighting = true;
    graph.setAutoPaint(false);

    const nodeItems = graph.getNodes();
    const edgeItems = graph.getEdges();

    // 重置 node 状态
    nodeItems.forEach((node) => {
      graph.setItemState(node, "dark", true);
      node.getModel().light = false;
    });
    graph.setItemState(item, "dark", false);
    model.light = true;
    // console.log("model", model, model1);

    // 重置 edge 状态
    edgeItems.forEach((item, idx) => {
      const source = item.getSource().getModel();
      const target = item.getTarget().getModel();
      if (source.light && target.light) {
        graph.setItemState(item, "dark", false);
      } else {
        graph.setItemState(item, "dark", true);
      }
    });
    model1.forEach((item, idx) => {
      const source = item.getSource().getModel();
      const target = item.getTarget().getModel();
      if (source.light && target.light) {
        console.log("light");
        graph.setItemState(item, "dark", false);
      } else {
        graph.setItemState(item, "dark", true);
      }
    });
    // 影响的下游提亮
    edgeItems.filter((edge) => {
      if (edge.getSource().getModel().id === model.id) {
        graph.setItemState(edge, "dark", false);
      }
    });

    graph.paint();
    graph.setAutoPaint(true);
  });

  graph.on("node:mouseleave", () => {
    if (highlighting) {
      const nodeItems = graph.getNodes();
      const edgeItems = graph.getEdges();
      highlighting = false;

      nodeItems.forEach((item) => {
        graph.setItemState(item, "dark", false);
      });
      edgeItems.forEach((item) => {
        graph.setItemState(item, "dark", false);
      });
    }
  });

  // 点击节点折叠或展开
  graph.on("node:click", (e) => {
    const item = e.item;
    //点击的节点实例
    const model = item.getModel();

    // 节点展开逻辑 如果单击一个根，隐藏不相关的项，并显示相关的项
    const layoutController = graph.get("layoutController");
    const forceLayout = layoutController.layoutMethods[0];
    forceLayout.forceSimulation.stop();

    // 单击同一节点即当前的焦点节点，隐藏小节点，将布局参数更改为根视图
    if (model.collapse) {
      model.collapse = false;
      // layoutController.layoutCfg.nodeStrength = -300;
      // layoutController.layoutCfg.collideStrength = 0.1;
      // layoutController.layoutCfg.alphaDecay = 0.01;

      const hideNodes = hideMap.get(model.id).hideNodes;
      const hideEdges = hideMap.get(model.id).hideEdges;

      curShowNodes = curShowNodes.concat(hideNodes);
      curShowEdges = curShowEdges.concat(hideEdges);
      console.log("uncollapse", curShowNodes, curShowEdges);
    } else {
      // 单击其他焦点节点，隐藏当前小节点，显示相关节点
      model.collapse = true;
      // 节点作用力，正数代表节点之间的引力作用，负数代表节点之间的斥力作用
      // layoutController.layoutCfg.nodeStrength = () => {
      //   return -300;
      // };
      // layoutController.layoutCfg.collideStrength = 0.1; //防止重叠力度

      // 找到被点击节点的后代节点
      let hideArr = findDownstreamNodes(model.id);
      // 隐藏不相关的节点和边
      const hideNodes = curShowNodes.filter((node) =>
        hideArr.includes(node.id)
      );
      const hideEdges = curShowEdges.filter((edge) =>
        hideArr.includes(edge.target)
      );
      hideMap.set(model.id, { hideNodes, hideEdges });

      curShowNodes = curShowNodes.filter((node) => !hideArr.includes(node.id));
      curShowEdges = curShowEdges.filter(
        (edge) => !hideArr.includes(edge.target)
      );
      console.log("collapse", model.collapse, curShowNodes, curShowEdges);

      setDisappearingState(hideEdges, hideNodes);
    }

    setTimeout(() => {
      graph.changeData({
        nodes: curShowNodes,
        edges: curShowEdges,
      });
      const nodeItems = graph.getNodes();
      const edgeItems = graph.getEdges();
      edgeItems.forEach((item) => {
        graph.clearItemStates(item);
      });
      nodeItems.forEach((item) => {
        graph.clearItemStates(item);
        graph.setItemState(item, "appearing", true);
      });
    }, 100);

    hideContextMenu();
  });

  graph.on("canvas:click", () => {
    const forceLayout = graph.get("layoutController").layoutMethods[0];
    forceLayout.forceSimulation.stop();
    const nodeItems = graph.getNodes();
    const edgeItems = graph.getEdges();
    if (highlighting) {
      highlighting = false;
      nodeItems.forEach((item) => {
        graph.setItemState(item, "dark", false);
      });
      edgeItems.forEach((item) => {
        graph.setItemState(item, "dark", false);
      });
    } else {
      nodeItems.forEach((item) => {
        graph.setItemState(item, "disappearing", true);
      });
      edgeItems.forEach((item) => {
        graph.setItemState(item, "disappearing", true);
      });

      setTimeout(() => {
        // 点击canvas，修改参数
        const layoutController = graph.get("layoutController");
        layoutController.layoutCfg.nodeStrength = 0;
        layoutController.layoutCfg.collideStrength = 0.1;
        layoutController.layoutCfg.alphaDecay = 0.01;

        // layoutController.layoutCfg.linkDistance = (d) => {
        //   //边长度
        //   return 180;
        // };
        // layoutController.layoutCfg.edgeStrength = () => {
        //   //边的作用力
        //   return 2;
        // };

        // 视图重置了，需要重新设置状态
        console.log("reset view");
        curShowNodes = showNodes.map((node) => {
          node.collapse = false;
          return node;
        });
        curShowEdges = showEdges;

        graph.changeData({
          nodes: curShowNodes,
          edges: curShowEdges,
        });
      }, 100);
    }
    hideContextMenu();
  });

  graph.on("canvas:mouseleave", () => {
    console.log("canvas:mouseleave");
  });
  //查找节点关联和级联节点
  function findDownstreamNodes(startNodeId) {
    // 创建一个Set用于存储已经访问过的节点ID，避免重复访问
    const visited = new Set();
    // 创建一个队列用于BFS遍历，初始化为包含起始节点
    const queue = [startNodeId];
    // 将起始节点标记为已访问
    visited.add(startNodeId);

    while (queue.length > 0) {
      // 从队列中取出第一个元素
      const currentId = queue.shift();
      // 遍历所有边，寻找与当前节点相关联的“target”节点（即下游节点）
      edges.forEach((edge) => {
        if (edge.source === currentId && !visited.has(edge.target)) {
          // 如果找到新的未访问下游节点，则加入到队列和已访问集合中
          visited.add(edge.target);
          queue.push(edge.target);
        }
      });
    }

    // 返回除起始节点外的所有下游关联和级联节点ID
    return Array.from(visited).filter((id) => id !== startNodeId);
  }

  // 生动地隐藏将要消失的节点和边
  function setDisappearingState(edges, nodes) {
    if (edges.length) {
      edges.forEach((csedge) => {
        const item = graph.findById(csedge.id);
        //应用隐藏动画
        item && graph.setItemState(item, "disappearing", true);
      });
    }

    nodes.forEach((csnode) => {
      const item = graph.findById(csnode.id);
      item && graph.setItemState(item, "disappearing", true);
    });
    graph.positionsAnimate();
  }
};

export const createContextMenu = () => {
  // 创建 ul
  var contextMenuContainer = $("<ul>", {
    id: "contextMenu",
  });

  // 创建 li
  var firstLi = $("<li>", {
    text: "菜单项1",
  });

  var lastLi = $("<li>", {
    text: "查看网元告警",
  });
 
  firstLi.addClass("layui-icon layui-icon-question");

  lastLi.addClass("layui-icon layui-icon-eye");

  // 将 li 添加到 ul
  contextMenuContainer.append(firstLi, lastLi);

  // 将 ul 添加到 body
  $("body").append(contextMenuContainer);

  $("#contextMenu").css("left", "-100px");
};

// 隐藏菜单
export const hideContextMenu = () => {
  $("#contextMenu")
    .css({ left: -100 + "px" })
    .removeAttr("nodeId");
};
